package system;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import bean.BlogBean;
import dao.BlogDAO;
import dao.DAO;

/**
 * Class responsible for the operations of user
 * @author Anne Lorayne, Laura Dutra, Otavio Lima
 * 
 */

// TODO Falta Busca e Doc
public class Blog {

	private static DAO<BlogBean> blogDAO = BlogDAO.getInstance();

	private List<Post> postList;
	private BlogBean blog;
	private List<Blog> subBlogs;

	/**
	 * Constructor
	 * 
	 * @param title
	 * @param description
	 * @param owner
	 * @throws Exception
	 *             if title is null or empty
	 */
	public Blog(String title, String description, String blogID, String owner)
	throws Exception {
		if (title == null || title.equals("")) {
			throw new Exception("Você deve especificar um título para o blog");
		} else {
			blog = new BlogBean(title, description, blogID, owner);
			blogDAO.save(blog);
		}
		postList = Post.getAllPostOfBlog(blogID);
		subBlogs = new ArrayList<Blog>(); //TODO Implement that
	}
	
	public Blog(BlogBean bean){
		blog = bean;
		postList = Post.getAllPostOfBlog(bean.getID());
		subBlogs = new ArrayList<Blog>(); //TODO Implement that
	}

	//TODO Dois updates, qual fica?
	/**
	 * Updates blog information
	 * 
	 * @param title
	 *            - title of blog
	 * @param description
	 *            - description of blog
	 * @return true if the blog was updated
	 */
	public boolean update(String title, String description) {
		if (title == null || title.trim().equals("")) {
			return false;
		}
		if (description == null) {
			return false;

		} else {
			blog.setTitle(title);
			blog.setDescription(description);
			return BlogDAO.getInstance().update(blog);
		}

	}
	
	/**
	 * Modifies the information of the blog passed as parameter
	 * @param attribute
	 * 			- Attribute will be modifies
	 * @param newValue
	 * 			- NewValue will be inserted
	 * @return true 
	 * 			- if the update was completed successfully
	 * 		   false
	 * 			- otherwise 
	 * @throws Exception
	 */
	public boolean updateBlog(String attribute, String newValue)
	throws Exception {
		Iterator<BlogBean> blogs = blogDAO.list().iterator();

		Map<String, String> pt_to_en = new HashMap<String, String>();

		{
			pt_to_en.put("titulo", "Title");
			pt_to_en.put("descricao", "Description");
			pt_to_en.put("dono", "Owner");
		}
		Object[] args = { newValue };
		try{
			Class blogBeanClass = blog.getClass();
			Method thisMethod = blogBeanClass.getMethod("set"
					+ pt_to_en.get(attribute),
					new Class[] { String.class });
			thisMethod.invoke(blog, args); // we can receive
			blogDAO.update(blog);
			return true;
		} catch (Exception e) {
			throw new Exception("Atributo inválido");
		}
	}
	
	/**
	 * Returns id of blog
	 * @return blogId
	 */
	public String getId(){
		return blog.getID();
	}

//Fix that

	/**
	 * Retrieves the information from the blog of the attribute passed as parameter
	 * @param blogID
	 * @param attribute
	 * @return blog's information
	 * @throws Exception
	 */
	@SuppressWarnings( { "rawtypes", "unchecked" })
	public static String getInformationBlog(String blogID, String attribute)
	throws Exception {

		Iterator<BlogBean> blogs = blogDAO.list().iterator();

		Map<String, String> pt_to_en = new HashMap<String, String>();

		{
			pt_to_en.put("titulo", "Title");
			pt_to_en.put("descricao", "Description");
			pt_to_en.put("dono", "Owner");
		}

		try {
			while (blogs.hasNext()) {
				BlogBean anotherBlog = blogs.next();
				if (anotherBlog.getID().equals(blogID)) {
					Class blogBeanClass = anotherBlog.getClass();

					Method thisMethod = blogBeanClass.getMethod("get"
							+ pt_to_en.get(attribute), (Class[]) null);

					Object result = thisMethod.invoke(anotherBlog,
							(Object[]) null); // we can receive a null
					return result.toString();
				} else
					;

			}
			throw new Exception("Atributo inválido");
		} catch (Exception e) {
			throw new Exception("Atributo inválido");
		}
	}
	
	/**
	 * Returns a list of all the user's blogs passed as parameter
	 * @param userId
	 * @return blogs list
	 * @throws Exception
	 */
	public static List<Blog> getAllBlogsOfUser(String userId) throws Exception{
		BlogBean blog;
		DAO<BlogBean> blogDAO;
		blogDAO = BlogDAO.getInstance();
		List<BlogBean> list = blogDAO.list();
		List<Blog> blogsByUser = new ArrayList<Blog>();
		for(Iterator<BlogBean> it = list.iterator(); it.hasNext();){
			blog = it.next();
			if(isBlogOfUser(userId, blog.getID()))
					blogsByUser.add(new Blog(blog));
		}
		return blogsByUser;
	}

	/**
	 * Delete the blog of system
	 */
	public void delete() {
		
		for (Iterator<Post> it = postList.iterator(); it.hasNext();)
			it.next().delete();
		
		for (Iterator<Blog> it = subBlogs.iterator(); it.hasNext();)
			it.next().delete();
		
		BlogDAO.getInstance().delete(blog);
	}

	/**
	 * Add a subblog to blog
	 * 
	 * @param title
	 *            - title of subblog
	 * @param description
	 *            - description of subblog
	 * @return true if subblog was added
	 * @throws Exception
	 *             invalid argument
	 */
	public String addSubBlog(String blogId, String title, String description)
	throws Exception {
		if(getId().equals(blogId)){
			String id = lastSubBlogId();
			subBlogs.add(0, new Blog(title, description, id, blog.getOwner()));
			return id;
		}
		
		Blog blog;
		for (Iterator<Blog> it = subBlogs.iterator(); it.hasNext();) {
			blog = it.next();
			if(blogId.contains(blog.getId()))
				return blog.addSubBlog(blogId, title, description);

		}
		throw new Exception("Blog invalido");
	}

	/**
	 * Add a post to blog
	 * 
	 * @param title
	 *            - title of post
	 * @param content
	 *            - content of post
	 * @return true if post was added
	 */
	public String addPost(String title, String content, String date) throws Exception{
		if (title == null || title.trim().equals(""))
			throw new Exception("Título obrigatório");

		String postId = lastPostId();
		postList.add(0, new Post(postId, title, content, date));
		return postId;
	}

	/**
	 * Returns post information for attribute
	 * @param postID - id of post
	 * @param attribute
	 * @return post information for attribute
	 * @throws Exception
	 */
	public String getPostInformation(String postID, String attribute) throws Exception{
		Iterator<Post> posts = postList.iterator();
		
		while (posts.hasNext()) {
			Post post = posts.next();
			if (post.getID().equals(postID))
				return post.getPostInformation(attribute);
		}
		throw new Exception("Post inválido");
	}


	/**
	 * Removes post of system
	 * 
	 * @param id
	 *            - id of post
	 * @return true if post was deleted
	 * @throws Exception 
	 */
	public void deletePost(String id) throws Exception {
		Post post = getPostObject(id);
		if(post == null)
			throw new Exception("Post inválido");
		postList.remove(post);
		post.delete();
	}

	/**
	 * Gets post by index
	 * 
	 * @param index
	 * @return return the post of index
	 */
	public String getPostId(int index) {
		if (index >= 0 && index < postList.size())
			return postList.get(0).getID();
		return null;
	}
	
	/**
	 * Checks if the blog post contains passed as parameter
	 * @param id
	 * @return true 
	 * 			- if blog contains post
	 * 		   false
	 * 			- otherwise
	 */
	public boolean hasPost(String id){
		return id.contains(getId());
	}

	/**
	 * Add picture to post
	 * 
	 * @param postId
	 *            - id of post
	 * @param data
	 *            - data of picture
	 * @param description
	 *            of picture
	 * @return true if picture was added
	 */
	public String addPictureToPost(String postId, String data,
			String description) {
		return getPostObject(postId).addPicture(data, description);
	}
	
	/**
	 * Returns the number of pictures in the post
	 * @param postId
	 * @return the number of pictures in the post
	 */
	public long getNumberOfPicturesOfPost(String postId) {
		return getPostObject(postId).getNumberOfPictures();
	}

	/**
	 * Returns picture at index
	 * @param index
	 * @return picture at index
	 * @throws Exception 
	 */
	public String getPicture(String postId, long index) throws Exception{
		Post post = getPostObject(postId); 
		return  post != null? post.getPictureId(index) : null ;
	}
	
	/**
	 * Returns sound at index
	 * @param postId
	 * @param index
	 * @return soundId
	 * @throws Exception
	 */
	public String getSound(String postId, long index) throws Exception {
		Post post = getPostObject(postId);
		return post != null? post.getSoundId(index) : null;
	
	}
	
	/**
	 * Returns movie at index
	 * @param postId
	 * @param index
	 * @return movieId
	 * @throws Exception
	 */
	public String getMovie(String postId, long index) throws Exception {
		Post post = getPostObject(postId);
		return post != null? post.getMovieId(index) : null;
	
	}

	/**
	 * Checks if the post picture contains passed as parameter
	 * @param id
	 * @return true 
	 * 			- if post contains picture
	 * 		   false
	 * 			- otherwise
	 */
	public boolean hasPicture(String pictureId) {
		Post post;
		for (Iterator<Post> it = postList.iterator(); it.hasNext();) {
			post = it.next();
			if (post.hasPicture(pictureId))
				return true;

		}
		return false;
	}
	

	/**
	 * Add movie to post
	 * 
	 * @param postId
	 *            - id of post
	 * @param data
	 *            - data of movie
	 * @param description
	 *            of movie
	 * @return true if picture was added
	 */
	public String addMovieToPost(String postId, String data, String description) {
		return getPostObject(postId).addMovie(data, description);
	}
	
	/**
	 * Returns the number of movies in the post
	 * @param postId
	 * @return the number of movies in the post
	 */
	
	public long getNumberOfMoviesOfPost(String postId) {
		return getPostObject(postId).getNumberOfMovies();
	}


	/**
	 * Add sound to post
	 * 
	 * @param postId
	 *            - id of post
	 * @param data
	 *            - data of sound
	 * @param description
	 *            of sound
	 * @return true if picture was added
	 */
	public String addSoundToPost(String postId, String data, String description) {
		
		return getPostObject(postId).addSound(data, description);
	}
	
	/**
	 * Returns the number of sounds in the post
	 * @param postId
	 * @return the number of sounds in the post
	 */
	public long getNumberOfSoundsOfPost(String postId) {
		return getPostObject(postId).getNumberOfSounds();
	}
	
	/**
	 * Checks if the post media contains passed as parameter
	 * @param id
	 * @return true 
	 * 			- if post contains media
	 * 		   false
	 * 			- otherwise
	 */
	public boolean hasMedia(String mediaId) {
		return mediaId.contains(getId());
	}

	/**
	 * Returns data's media passed as parameter
	 * @param mediaId
	 * @return data's media
	 */
	public String getMediaData(String mediaId) {
		Post post = getPostObject(mediaId.substring(0, mediaId.indexOf("m")));
		return post != null? post.getMediaData(mediaId) : null;
	}


	/**
	 * Returns description's media passed as parameter
	 * @param mediaId
	 * @return description's media
	 */
	public String getMediaDescription(String mediaId) {
		Post post = getPostObject(mediaId.substring(0, mediaId.indexOf("m")));
		return post != null? post.getMediaDescription(mediaId) : null;
	}


	// TODO removes of add up there

//	public boolean addCommentToPost() {
//		return false;
//	}

//	public boolean addCommentToComment() {
//		return false;
//	}


	/**
	 * Checks if the post sound contains passed as parameter
	 * @param id
	 * @return true 
	 * 			- if post contains sound
	 * 		   false
	 * 			- otherwise
	 */
	public boolean hasSound(String id){
		Post post;
		for (Iterator<Post> it = postList.iterator(); it.hasNext();) {
			post = it.next();
			if (post.hasSound(id))
				return true;

		}
		return false;
	}
	
	//Private methods

	/**
	 * Returns the last postId
	 * @return last postId
	 */
	private String lastPostId() {
		blog.setLastPostId(String.valueOf(Integer.parseInt(blog.getLastPostId())+1));
		blogDAO.update(blog);
		String id = blog.getID() + "p" + blog.getLastPostId();
		return id;
	}

	//TODO Implements that
	/**
	 * Returns id of sub blog
	 * @return last id of blog
	 */
	private String lastSubBlogId() {
		return getId() + "b";
	}
	

	/**
	 * Retrieves the post with the id passed as parameter equal to
	 * @param postId
	 * @return Post 
	 */
	private Post getPostObject(String postId) {
		Post post;
		
		for (Iterator<Post> it = postList.iterator(); it.hasNext();) {
			post = it.next();
			
			if (post.getID().equals(postId))
				return post;

		}
		return null;
	}

	
	/**
	 * Returns boolean if is user's blog
	 * @param id
	 * @param blogId
	 * @return
	 */
	private static boolean isBlogOfUser(String id, String blogId) {
		return blogId.contains(id);
			
	}

	//US 7
	/**
	 * Returns the number of blog posts
	 * @return number of posts
	 * @throws Exception
	 */
	public int getNumberOfPosts() {
		return postList.size();
	}

	/**
	 * Capturing the post with the index passed as parameter
	 * @param index
	 * 			- Post's index
	 * @return postId
	 */
	public String getPostAtIndex(int index) {
		if(index < 0 || index > postList.size())
			return null; //throw new Exception("Index invalido") 
		return postList.get(index).getID();
	}
	
	/**
	 * Delete a movie
	 * @param movieId
	 * 			- Identifier of the movie will be deleted
	 */
	public void deleteMovie(String movieId) {
		Post post = getPostObject(movieId.substring(0, movieId.indexOf("m")));
		if(post != null){
			post.removeMovie(movieId);
		}
	}

	/**
	 * Delete a sound
	 * @param soundId
	 * 			- Identifier of the sound will be deleted
	 */
	public void deleteSound(String soundId) {
		Post post = getPostObject(soundId.substring(0, soundId.indexOf("m")));
		if(post != null)
			post.removeSound(soundId);
	}
	/**
	 * Delete a picture
	 * @param pictureId
	 * 			- Identifier of the picture will be deleted
	 */
	public void deletePicture(String pictureId) {
		Post post = getPostObject(pictureId.substring(0, pictureId.indexOf("m")));
		if(post != null)
			post.removePicture(pictureId);
	}

	/**
	 * Add a comment
	 * @param postId
	 * 			- identifier of the post which is inserted into the comment
	 * @param comment
	 * 			- Text's comment
	 * @return
	 * @throws Exception
	 */
	public String addComment(String postId, String comment, String login) {
		Post post = getPostObject(postId);
		if(post != null)
			return post.addComment(comment, login);
		return null;
	}
	
	/**
	 * Returns the number of comments of post
	 * @param postId
	 * 			- Identifier of the post which will capture the number of comments
	 * @return number of posts
	 * @throws Exception
	 */
	public long getNumberOfComments(String postId) {
		Post post = getPostObject(postId);
		if(post != null)
			return post.getNumberOfComments();
		return 0;
	}

	/**
	 * Capturing the comment with the index passed as parameter
	 * @param postId
	 * 			- Identifier of the post which will capture the comment
	 * @param index
	 * 			- comment's index
	 * @return commentId
	 */
	public String getComment(String postId, int index) {
		Post post = getPostObject(postId);
		if(post != null)
			return post.getComment(index);
		return null;
	}

	/**
	 * Checks if the post comment contains passed as parameter
	 * @param id
	 * @return true 
	 * 			- if post contains comment
	 * 		   false
	 * 			- otherwise
	 */
	public boolean hasComment(String commentId) {
		return commentId.contains(getId());
		//		Post post = getPostObject(commentId.substring(0, commentId.indexOf("c")));
//		if(post != null)
//			return post.hasComment(commentId);
//		return false;
	}

	/**
	 * Retrieves the comment's text passed as parameter
	 * @param commentId
	 * 			- identifier of the comment that the text will be recovered
	 * @return comment's text
	 * @throws Exception
	 */
	public String getCommentText(String commentId) throws Exception {
		Post post = getPostObject(commentId.substring(0, commentId.indexOf("c")));
		if(post != null)
			return post.getCommentText(commentId);
		throw new Exception("Comentário inválido");
	}
	
	/**
	 * Modifies the information of the post passed as parameter
	 * @param postId
	 * 			- Identifier of the post modification
	 * @param attribute
	 * 			- Attribute to be modified
	 * @param value
	 * 			- Value that will be inserted
	 * @throws Exception
	 */
	public void changePostInformation(String postId, String attribute,
			String value) throws Exception {
		Post post = getPostObject(postId);
		if(post == null)
			throw new Exception("Post Invalido");
		post.update(attribute, value);
		
	}

	/**
	 * Retrieves the comment's author passed as parameter
	 * @param commentId
	 * 			- identifier of the comment that the author will be recovered
	 * @return comment's author
	 * @throws Exception
	 */
	public String getCommentAuthor(String commentId) throws Exception {
		Post post = getPostObject(commentId.substring(0, commentId.indexOf("c")));
		if(post != null)
			return post.getCommentAuthor(commentId);
		throw new Exception("Comentário inválido");
		
	}

	/**
	 * Returns the number of comments by login
	 * @param login
	 * @return number of comments 
	 */
	public int getNumberOfCommentsByLogin(String login) {
		int numberOfComments = 0;
		for (Iterator<Post> it = postList.iterator(); it.hasNext();) {
			numberOfComments += it.next().getNumberOfCommentsByLogin(login);
			
		}
		return numberOfComments;
	}

	//US14
	
	/**
	 * Returns a object of sub blog
	 * @param blogId
	 * @return Blog
	 * @throws Exception
	 */
	public Blog getSubBlogObject(String blogId) throws Exception{
		if(blogId.equals(getId()))
			return this;
		Blog blog;
		for (Iterator<Blog> it = subBlogs.iterator(); it.hasNext();) {
			blog = it.next();
			if(blogId.contains(blog.getId()))
				return blog.getSubBlogObject(blogId);
			
		}
		throw new Exception("Blog invalido");		
	}
	
	/**
	 * Returns the number of sub blogs
	 * @param blogId
	 * @return number of sub blogs
	 * @throws Exception
	 */
	public int getNumberOfSubBlogs(String blogId) throws Exception{
		return getSubBlogObject(blogId).subBlogs.size();
		
	}
	
	/**
	 * Retuns a number of all sub blogs
	 * @param blogId
	 * @return number of all sub blogs
	 * @throws Exception
	 */
	public int getNumberOfAllSubBlogs(String blogId) throws Exception{
		if(blogId.equals(getId())){
			int numberOfSubBlogs = subBlogs.size();
			Blog b;
			for(Iterator<Blog> it = subBlogs.iterator(); it.hasNext();){
				b = it.next();
				numberOfSubBlogs += b.getNumberOfAllSubBlogs(b.getId());
			}
			System.out.println();
			return numberOfSubBlogs;
		}
		Blog blog;
		for (Iterator<Blog> it = subBlogs.iterator(); it.hasNext();) {
			blog = it.next();
			if(blogId.contains(blog.getId()))
				return blog.getNumberOfAllSubBlogs(blogId);

		}
		throw new Exception("Blog inválido");
		
		
	}

	/**
	 * Returns the number of sub blog of blogId and index passed as parameter
	 * @param blogId
	 * @param index
	 * @return id of sub blog
	 * @throws Exception
	 */
	public String getSubBlog(String blogId, int index) throws Exception{
		if(blogId.equals(getId())){
			if(index < 0 || index >=subBlogs.size())
				throw new Exception("Indice invalido");
			return subBlogs.get(index).getId();
		}
		Blog blog;
		for (Iterator<Blog> it = subBlogs.iterator(); it.hasNext();) {
			blog = it.next();
			if(blogId.contains(blog.getId()))
				return blog.getSubBlog(blogId, index);

		}
		throw new Exception("Blog inválido");

	}

	/**
	 * Returns the number of all posts of blogId passed as parameter
	 * @param blogId
	 * @return number of all posts
	 * @throws Exception
	 */
	public int getNumberOfAllPosts(String blogId) throws Exception {
		if(blogId.equals(getId())){
			int numberOfAllPosts = 0;
			Blog blog;
			for (Iterator<Blog> it = subBlogs.iterator(); it.hasNext();) {
				blog = it.next();
				numberOfAllPosts += blog.getNumberOfAllPosts();
			}
			return numberOfAllPosts += postList.size();
		}
		throw new Exception("Blog inválido");
	}

	/**
	 * Returns the number of all posts
	 * @return number of all posts
	 */
	private int getNumberOfAllPosts() {
		return postList.size();
		
	}

}

